package user

import (
	"github.com/labstack/echo"
	auth "tacitus/library/authorized"
	"tacitus/library/error"
	resp "tacitus/library/response"
	"tacitus/library/short"
	"time"
)

func SendCaptchaHandler(c echo.Context) error {
	i := new(struct{
		Mobile string `json:"mobile"`
		Action string `json:"action"`
	})
	if err := c.Bind(i); err != nil {
		return err
	}
	// 检查是否频繁发送
	record := new(Captcha)
	if ok, err := x.Where("mobile = ?", i.Mobile).Where("create_time >= ?", time.Now().Unix()-60).Get(record); err != nil {
		return err
	} else if ok {
		return errs.Called("操作过于频繁，请稍后再试")
	}
	// 检查绑定时有没有被占用
	if i.Action == "bind" {
		u := new(User)
		if ok, err := x.Where("mobile = ?", i.Mobile).Get(u); err != nil {
			return err
		} else if ok {
			return errs.Called("手机号已被占用")
		}
	}
	// 生成验证码
	ca := &Captcha{
		Mobile:     i.Mobile,
		Action:     i.Action,
		Code:       RandCaptcha(),
		CreateTime: time.Now().Unix(),
	}
	if _, err := x.Insert(ca); err != nil {
		return err
	}
	// TODO 发送验证码
	return nil
}

func LoginByMobileHandler(c echo.Context) error {
	i := new(struct{
		Mobile string `json:"mobile"`
		Code string `json:"code"`
	})
	if err := c.Bind(i); err != nil {
		return err
	}
	// 检查在有效期之内的验证码
	record := new(Captcha)
	if ok, err := x.Where("mobile = ? AND action = 'login'", i.Mobile).Where("create_time >= ?", time.Now().Unix()-600).OrderBy("create_time DESC").Get(record); err != nil {
		return err
	} else if !ok {
		return errs.Called("请先发送验证码")
	}
	if record.Code != i.Code {
		return errs.Called("验证码错误")
	}
	if _, err := x.Where("id = ?", record.ID).Update(&Captcha{Used: 1}); err != nil {
		return err
	}
	// 检查是否有绑定用户
	u := new(User)
	if ok, err := x.Where("mobile = ?", i.Mobile).Get(u); err != nil {
		return err
	} else if !ok {
		// 手机号未被绑定，请绑定已有用户或创建新用户
		return resp.Data(c, echo.Map{
			"captcha_code": short.Encode(record.ID),
		})
	}
	// 生成token
	token := auth.Generate(auth.Claims{
		UserID:            u.ID,
		Account:           u.Account,
		AccessControlList: "*",
		Extends:           nil,
	})
	login := &Login{
		UserID:     u.ID,
		IP:         c.RealIP(),
		Token:      token,
		CreateTime: time.Now().Unix(),
	}
	if _, err := x.Insert(login); err != nil {
		return err
	}
	return resp.Data(c, echo.Map{
		"token": token,
	})
}

// 已检查验证码，直接用手机号创建新用户
func CreateNewByMobileHandler(c echo.Context) error {
	i := new(struct{
		CaptchaCode string `json:"captcha_code"`
	})
	if err := c.Bind(i); err != nil {
		return err
	}
	id, err := short.Decode(i.CaptchaCode)
	if err != nil {
		return err
	}
	record := new(Captcha)
	if ok, err := x.Where("id = ?", id).Get(record); err != nil {
		return err
	} else if !ok {
		return errs.Called("验证码不存在")
	}
	u := new(User)
	if ok, err := x.Where("mobile = ?", record.Mobile).Get(u); err != nil {
		return err
	} else if ok {
		return errs.Called("手机号已被占用")
	}
	salt := RandSlat()
	password := RandPassword()
	u2 := &User{
		Account:    "m_"+record.Mobile,
		Password:   EncryptPassword(password, salt),
		Salt:       salt,
		Mobile:     record.Mobile,
		CreateTime: time.Now().Unix(),
	}
	if _, err := x.Insert(u2); err != nil {
		return errs.Report("xorm", err)
	}
	// 生成token
	token := auth.Generate(auth.Claims{
		UserID:            u2.ID,
		Account:           u2.Account,
		AccessControlList: "*",
		Extends:           nil,
	})
	login := &Login{
		UserID:     u2.ID,
		IP:         c.RealIP(),
		Token:      token,
		CreateTime: time.Now().Unix(),
	}
	if _, err := x.Insert(login); err != nil {
		return err
	}
	return resp.Data(c, echo.Map{
		"token": token,
	})
}

// 已检查验证码，绑定已有用户
func BindByMobileHandler(c echo.Context) error {
	i := new(struct{
		CaptchaCode string `json:"captcha_code"`
		Account  string `json:"account"` // 帐号，不能重复
		Password string `json:"password"` // 密码，只能保存加密后的密码
	})
	if err := c.Bind(i); err != nil {
		return err
	}
	id, err := short.Decode(i.CaptchaCode)
	if err != nil {
		return err
	}
	record := new(Captcha)
	if ok, err := x.Where("id = ?", id).Get(record); err != nil {
		return err
	} else if !ok {
		return errs.Called("验证码不存在")
	}
	u2 := new(User)
	if ok, err := x.Where("mobile = ?", record.Mobile).Get(u2); err != nil {
		return err
	} else if ok {
		return errs.Called("手机号已被占用")
	}

	u := new(User)
	if ok, err := x.Where("account = ?", i.Account).Get(u); err != nil {
		return errs.Report("xorm", err)
	} else if !ok {
		return errs.Called("用户帐号不存在")
	}

	if EncryptPassword(i.Password, u.Salt) != u.Password {
		return errs.Called("帐号密码错误")
	}

	// 修改手机号
	if _, err := x.Where("id = ?", u.ID).Update(&User{Mobile: record.Mobile}); err != nil {
		return err
	}

	token := auth.Generate(auth.Claims{
		UserID:            u.ID,
		Account:           u.Account,
		AccessControlList: "*",
		Extends:           nil,
	})
	login := &Login{
		UserID:     u.ID,
		IP:         c.RealIP(),
		Token:      token,
		CreateTime: time.Now().Unix(),
	}
	if _, err := x.Insert(login); err != nil {
		return err
	}
	return resp.Data(c, echo.Map{
		"token": token,
	})
}

// 已登录用户，绑定手机号
func BindMobileHandler(c echo.Context) error {
	uid := auth.CurrentUser(c).UserID
	i := new(struct{
		CaptchaID int64 `json:"captcha_id"`
	})
	if err := c.Bind(i); err != nil {
		return err
	}
	record := new(Captcha)
	if ok, err := x.Where("id = ?", i.CaptchaID).Get(record); err != nil {
		return err
	} else if !ok {
		return errs.Called("验证码不存在")
	}
	u2 := new(User)
	if ok, err := x.Where("mobile = ?", record.Mobile).Get(u2); err != nil {
		return err
	} else if ok {
		return errs.Called("手机号已被占用")
	}
	// 修改手机号
	if _, err := x.Where("id = ?", uid).Update(&User{Mobile: record.Mobile}); err != nil {
		return err
	}
	return nil
}